package asteroids.entity.weapon;

import java.awt.Color;

import org.apache.log4j.Logger;

import asteroids.engine.GameState;
import asteroids.engine.Utils;
import asteroids.entity.GameObject;
import asteroids.entity.Icing;
import asteroids.entity.PlayerShip;
import asteroids.entity.Ship;

public class LazerWeapon extends Weapon
{
    private static final Logger logger = Logger.getLogger(LazerWeapon.class);
    private final double BULLET_POWER;
    private final int BULLET_RANGE;
    private final boolean ROTARY;
    private int currentHardPoint = 0;
    Color BULLET_COLOR = Color.red;

    public LazerWeapon(Ship ship, double bulletPower, double energyCost, int refireDelay,
            boolean rotateHardpoints, int range)
    {
        super(ship, energyCost, refireDelay);
        BULLET_RANGE = range;
        BULLET_POWER = bulletPower;
        ROTARY = rotateHardpoints;
    }

    @Override
    public boolean FIRE(GameState state)
    {
        boolean fired = false;
        if( canFireYet(state) )
        {
            manageFireControl(state);
            fired = true;

            Utils.PolarCoordinate[] hardPoints = ((PlayerShip) ship).getHardPoints();

            if( ROTARY ) // then only fire from one hardpoint at a time
            {
                Utils.CartesianCoordinate firePoint = Utils.cartesianFromPolar(
                        hardPoints[currentHardPoint].rotateBy(ship.getRotation())).shiftBy(
                        ship.getXPosition(), ship.getYPosition());
                Bullet bill = new LazBullet(firePoint.getXComponent(), firePoint.getYComponent(),
                        ship.getRotation(), BULLET_POWER, BULLET_RANGE, ship);
                bill.setColor(BULLET_COLOR);
                if( Math.random() * 2 >= 1 )
                {
                    BULLET_COLOR = Color.yellow;
                }
                else
                {
                    BULLET_COLOR = Color.red;
                }
                ship.add(bill);
                currentHardPoint = (currentHardPoint + 1) % hardPoints.length;
            }
            else
            // fire from all hardpoints!
            {
                for( Utils.PolarCoordinate currentFirePoint : hardPoints )
                {
                    Utils.CartesianCoordinate firePoint = Utils.cartesianFromPolar(
                            currentFirePoint.rotateBy(ship.getRotation())).shiftBy(
                            ship.getXPosition(), ship.getYPosition());
                    Bullet bill = new LazBullet(firePoint.getXComponent(),
                            firePoint.getYComponent(), ship.getRotation(), BULLET_POWER,
                            BULLET_RANGE, ship);
                    bill.setColor(BULLET_COLOR);
                    if( Math.random() * 2 >= 1 )
                    {
                        BULLET_COLOR = Color.yellow;
                    }
                    else
                    {
                        BULLET_COLOR = Color.red;
                    }
                    ship.add(bill);
                }
            }
        }
        return fired;
    }
}

class LazBullet extends Bullet
{
    // private static Logger logger = Logger.getLogger(LazBullet.class);

    private final Ship owner;
    private boolean friendlyFire = false;
    private final int leRange;
    private final boolean shorten;
    private final int maxSparks;

    // private final double rotation;

    public LazBullet(double x, double y, double direction, double power, int range, int numSparks,
            boolean ifShortens, Ship ship)
    {
        super(getXCenter(x, range, direction), getYCenter(y, range, direction), direction, 0.0,
                power, 0, Utils.scalePolarShape(basicBulletShape, range), ship);
        leRange = range;
        shorten = ifShortens;
        rotation = direction;
        maxSparks = numSparks;
        owner = ship;
        drawMe = true;
    }

    public LazBullet(double x, double y, double direction, double power, int range,
            boolean ifShortens, Ship ship)
    {
        this(x, y, direction, power, range, range / 5, true, ship);
    }

    public LazBullet(double x, double y, double direction, double power, int range, Ship ship)
    {
        this(x, y, direction, power, range, true, ship);
    }

    public LazBullet(double x, double y, double direction, int range, boolean ifShortens, Ship ship)
    {
        this(x, y, direction, 1, range, ifShortens, ship);
    }

    public LazBullet(double x, double y, double direction, int range, Ship ship)
    {
        this(x, y, direction, 1, range, true, ship);
    }

    static private double getXCenter(double x, int range, double direction)
    {
        Utils.PolarCoordinate p = Utils.createPolarCoordinate(direction, range / 2);
        return x + Utils.cartesianFromPolar(p).getXComponent();
    }

    static private double getYCenter(double y, int range, double direction)
    {
        Utils.PolarCoordinate p = Utils.createPolarCoordinate(direction, range / 2);
        return y + Utils.cartesianFromPolar(p).getYComponent();
    }

    @Override
    public void collide(GameObject other, double power)
    {
        // logger.trace(this + " hit " + other);
        boolean friendlyObject = ((!friendlyFire && other.getType() != GameObject.ObjectType.BULLET && other
                .getAffiliation().equals(affiliation)));

        if( other.getType() != ObjectType.ICING && !invincible )
        {
            if( objectType == GameObject.ObjectType.SHIP )
            {
                // logger.warn(this + " was hit!!");
            }
            damage(power);
        }
        if( integrity <= 0 )
        {
            other.modifyScoreBy(value);
            power = 0;
        }

        // if we aren't trading off with another bullet, just die (unless it's a
        // friendly ship)
        if( other.getType() != GameObject.ObjectType.BULLET && !friendlyObject )
        {
            power = 0;
            if( shorten )
            {
                setObjectShape(Utils.scalePolarShape(
                        getObjectShape(),
                        Utils.pointDistance(x_position, y_position, other.getXPosition(),
                                other.getYPosition())
                                / leRange));
            }
        }
    }

    @Override
    public void update()
    {
        super.update();
        // create icing sparklies
        // int numSparks = (int) ((owner.getEnergy() / (owner.getMaxEnergy())) *
        // maxSparks);
        int numSparks = maxSparks;
        // make cool effects
        for( int i = 0; i < numSparks; i++ )
        {
            // double trueX = x_position; // start with X coordinate of the
            // beam's gun aperture
            double trueX = x_position - getXCenter(0, leRange, rotation);
            // double trueY = y_position; // start with Y coordinate of gun
            // barrel
            double trueY = y_position - getYCenter(0, leRange, rotation);

            double PIdir = (rotation) * Math.PI / 180; // find the rotation in
                                                       // radians

            double dist = (Math.random() * leRange); // decide how far down the
                                                     // beam we go

            trueX = trueX + dist * Math.cos(PIdir); // add that distance
                                                    // adjusted down
            trueY = trueY + dist * Math.sin(PIdir); // due to rotation

            double wide = ((Math.random() - 0.5) * 7); // decide how far we want
                                                       // to be from the beam
            trueX = trueX + wide * Math.sin(PIdir); //
            trueY = trueY - wide * Math.cos(PIdir); // DOO IIT!

            if( color == Color.red )
            {
                color = Color.yellow;
            }
            else
            {
                color = Color.red;
            }

            Icing b = new Icing(trueX, trueY, 0);
            b.setColor(color);
            owner.addIcing(b);
        }
    }

    public String toString()
    {
        return "lazah";
    }
}
